home *** CD-ROM | disk | FTP | other *** search
- /**
- ** Copyright 1985 - 1987 by the Massachusetts Institute of Technology
- **
- ** Permission to use, copy, modify, and distribute this software and
- ** its documentation for any purpose and without fee is hereby
- ** granted, provided that the above copyright notice appear in all
- ** copies and that both that copyright notice and this permission
- ** notice appear in supporting documentation, and that the name of
- ** M.I.T. not be used in advertising or publicity pertaining to
- ** distribution of the software without specific, written prior
- ** permission. M.I.T. makes no representations about the suitability
- ** of this software for any purpose. It is provided "as is" without
- ** express or implied warranty.
- **
- ** Original Author:
- ** Todd Brunhoff, Tektronix, inc.
- ** While a guest engineer at Project Athena, MIT
- **
- ** Modified by:
- ** Martin Neath, Texas Instruments Incorporated.
- **
- ** Introduction:
- ** =============
- ** Imake uses the C preprocessor on a macro-makefile (the Imakefile)
- ** to generate a Makefile for a particular system. Imake uses a
- ** predefined template file for default values, command names and
- ** procedures, and macros for a specific system. An Imakefile is
- ** system-independent; support for a new operating system or tool
- ** requires only the addition of a template file for that system. The
- ** Imakefile that specifies the dependencies and relationships between
- ** files in the software system to built does not change.
- **
- ** Options:
- ** -D define a symbol for the preprocessor
- ** -I specify include directory for the preprocessor
- **
- ** Usage: imake -D<machine> -DTOPDIR=<dirname> -DREV=<num> -I<config>
- **
- ** Imake is invoked with four arguments: a symbol defining the machine
- ** on which it is being run, a symbol TOPDIR assigned the name of the
- ** top directory of the source tree, a symbol REV assigned the current
- ** major RCS revision number, and an include search directory path to
- ** be search for the template and configuration files.
- **
- ** Changes From X11R4 Distribution:
- ** ===============================
- **
- ** This version of Imake is quite different to the original version on
- ** the X11R4 source tape. As originaly implemented, Imake only ran on
- ** UNIX-like operating systems, for example assuming that the program
- ** /lib/cpp was the location of the C preprocessor. This version has
- ** been significantly modified to run on non-UNIX operating systems to
- ** enhance is usage. Thus, the preprocessor has been internalized and
- ** is now a subroutine call. File names are case insensitive and do
- ** not violate the "eight dot three" name rule for OS/2 and MS-DOS.
- ** Finally, the strings "@@", "@+", "@-", "@#", and "@!" are used to
- ** denote the end of line, integer increment, integer decrement, make
- ** comment line, and escaped-double-quote. These are processed after
- ** the preprocessor is run with the appropriate characters inserted
- ** into the generated Makefile.
- **
- ** Theory of Operation:
- **
- ** 1) Start up Imake and process the command line directives checking
- ** for four arguments specifying machine/system name, the tope of
- ** the source directory, a revision number, and a directory path.
- **
- ** 2) Call the preprocessor and provide it with three lines of input:
- **
- ** #define IMAKE_TEMPLATE "<Imakefile>"
- ** #define INCLUDE_IMAKEFILE < <imakefile> >
- ** #include IMAKE_TEMPLATE
- **
- ** Note that the define for INCLUDE_IMAKEFILE is intended for use
- ** in the template file. The design of the template makefile should
- ** therefore be:
- **
- ** <set global macros like CFLAGS, etc.>
- ** <include machine dependent additions>
- ** #include INCLUDE_IMAKEFILE
- ** <add any global targets like 'clean' and long dependencies>
- **
- ** 3) Gather the output from preprocessor and clean it up, expanding
- ** @@ to newlines, @# to make comment lines, @+ and @- to either
- ** increment or decrement, respectively, an integer number, and
- ** stripping trailing white space, cpp control lines, and extra
- ** blank lines. This cleaned output is copied to the Makefile.
- **/
-
- #include <stdio.h>
- #include <ctype.h>
-
- #ifdef os2
- #include <sys/types.h>
- #include <fcntl.h>
- #include <signal.h>
- #include <sys/stat.h>
- #else /* !os2 */
- #ifdef VMS
- #include <types.h>
- #include <file.h>
- #include <signal.h>
- #include <stat.h>
- #else /* ! VMS */
- #include <sys/types.h>
- #ifdef SYSV
- #ifndef macII /* mac will get the stuff out of file.h */
- #include <fcntl.h>
- #endif
- #else /* !SYSV */
- #include <sys/wait.h>
- #endif /* !SYSV */
- #include <sys/file.h>
- #include <signal.h>
- #include <sys/stat.h>
- #endif /* VMS */
- #endif /* os2 */
-
- #include "pimake.h"
-
-
- #define TRUE 1
- #define FALSE 0
-
- int InRule = FALSE;
-
- typedef unsigned char boolean;
-
- #ifdef VMS
- #define CPP_PROGRAM "mcr [-.cpp]cpp"
- #endif
- char *cpp = CPP_PROGRAM;
-
- char *tmpImakefile = NULL;
- char *tmp_file_name = "temp.tmp";
- char *tmp_mkfile_name = "makefile.tmp";
-
- int cpp_argindex;
- char *Imakefile = "Imakefile";
- char *Makefile = "Makefile";
- char *Template = "imake.imk";
- char *program;
- char *FindImakefile();
- char *ReadLine();
- char *CleanCppInput();
- char *strdup();
-
- void LogFatal();
-
- extern int errno;
- extern char *Emalloc();
- extern char *realloc();
- extern char *mktemp();
-
- #ifdef VMS
- /* dzg - added this routine, which is not defined in VMS
- */
- void unlink (name)
- char *name;
- {
- char command[200];
- /* Use the DELETE command (executed through SYSTEM), since VMS does not
- support UNLINK */
- sprintf (command, "delete %s;", name);
- system (command);
- }
- #endif
-
-
-
- main(argc, argv)
- int argc;
- char **argv;
- {
- init();
- if( argc != 5) {
- fprintf(stderr, "Usage: pimake -D<machine> -DTOPDIR=<dirname> -DREV=<num> -I<config>\n");
- exit(-1);
- }
- SetOpts(argc, argv);
-
- Imakefile = FindImakefile(Imakefile);
-
- cppit(Imakefile, Template);
- if (tmpImakefile != NULL)
- unlink(tmpImakefile);
- if (tmp_file_name != NULL)
- unlink(tmp_file_name);
- if (tmp_mkfile_name != NULL)
- unlink(tmp_mkfile_name);
- exit(0);
- }
-
- #if SIGNALRETURNSINT
- int
- #else
- void
- #endif
- catch(sig)
- int sig;
- {
- errno = 0;
- LogFatalI("Signal %d.", sig);
- }
-
-
- /*
- * Initialize some variables.
- */
- init()
- {
- char *p;
-
- cpp_argindex = 0;
- while (cpp_argv[ cpp_argindex ] != NULL)
- cpp_argindex++;
- #ifndef os2
- if (signal(SIGINT, SIG_IGN) != SIG_IGN)
- signal(SIGINT, catch);
- #endif
- }
-
- AddCppArg(arg)
- char *arg;
- {
- errno = 0;
- if (cpp_argindex >= ARGUMENTS-1)
- LogFatal("Out of internal storage.", "");
- cpp_argv[ cpp_argindex++ ] = arg;
- cpp_argv[ cpp_argindex ] = NULL;
- }
-
- SetOpts(argc, argv)
- int argc;
- char **argv;
- {
- char* TOPDIR[100];
- errno = 0;
- program = argv[0];
- AddCppArg("-I.");
- for(argc--, argv++; argc; argc--, argv++) {
- if (argv[0][0] == '-') {
- if (argv[0][1] == 'D') {
- AddCppArg(argv[0]);
- /** if( !strcmp(&argv[0][2], "TOPDIR=" )) {
- ** strcpy( TOPDIR, "-I" );
- ** strcat( TOPDIR, &argv[0][2] );
- ** AddCppArg( TOPDIR );
- ** }
- **/
- } else if (argv[0][1] == 'I') {
- AddCppArg(argv[0]);
- }
- }
- else if (argv[0][0] == '/') {
- if (argv[0][1] == 'D') {
- AddCppArg(argv[0]);
- } else if (argv[0][1] == 'I') {
- AddCppArg(argv[0]);
- }
- }
- }
- }
-
- char *FindImakefile(Imakefile)
- char *Imakefile;
- {
- int fd;
-
- if ((fd = open(Imakefile, O_RDONLY)) < 0)
- LogFatal("Cannot open %s.", Imakefile);
- close (fd);
- return(Imakefile);
- }
-
- LogFatalI(s, i)
- char *s;
- int i;
- {
- /*NOSTRICT*/
- LogFatal(s, (char *)i);
- }
-
- void
- LogFatal(x0,x1)
- char *x0, *x1;
- {
- #ifndef VMS
- extern char *sys_errlist[];
- #endif
- static boolean entered = FALSE;
-
- if (entered)
- return;
- entered = TRUE;
-
- fprintf(stderr, "%s: ", program);
- #ifndef VMS
- if (errno)
- fprintf(stderr, "%s: ", sys_errlist[ errno ]);
- #endif
- fprintf(stderr, x0,x1);
- fprintf(stderr, " Stop.\n");
- unlink(tmpImakefile);
- exit(1);
- }
-
- cppit(Imakefile, template)
- char *Imakefile;
- char *template;
- {
- char *cleanedImakefile;
- char command[200];
- int i;
- FILE *outfd;
-
- /* Exec the C preprocessor */
- cleanedImakefile = CleanCppInput(Imakefile, template);
-
- /* Execute the C preprocessor */
- strcpy (command, cpp);
- for (i = 2; i < cpp_argindex; ++i) {
- #ifdef VMS
- strcat (command, " \"");
- #else
- strcat (command, " ");
- #endif
- strcat (command, cpp_argv[i]);
- #ifdef VMS
- strcat (command, " \"");
- #else
- strcat (command, " ");
- #endif
- }
- strcat (command, " ");
- strcat (command, tmp_file_name);
- strcat (command, " ");
- strcat (command, tmp_mkfile_name);
- system (command);
-
- if ((outfd = fopen(Makefile, "w+")) == NULL)
- LogFatal("Cannot create makefile %s.", Makefile);
- CleanCppOutput (outfd, Makefile);
- }
-
-
- char *CleanCppInput(Imakefile, template)
- char *Imakefile, *template;
- {
- FILE *outFile = NULL;
- FILE *infd;
- int length;
- int i;
- char *buf, /* buffer for file content */
- *start, /* starting point of actual file data */
- *pbuf, /* walking pointer to buf */
- *punwritten, /* pointer to unwritten portion of buf */
- *cleanedImakefile = Imakefile,/* return value */
- *ptoken, /* pointer to # token */
- *pend, /* pointer to end of # token */
- savec; /* temporary character holder */
- struct stat st;
- FILE *tmpfile;
-
- if ((infd = fopen(Imakefile, "r")) == NULL)
- LogFatal("Cannot open %s for input.", Imakefile);
- if ((tmpfile = fopen (tmp_file_name, "w")) == NULL)
- LogFatal("Cannot open %s for output.", tmp_file_name);
-
- stat (Imakefile, &st);
- buf = Emalloc(st.st_size+1);
- /* Add the first three lines */
- fprintf (tmpfile, "#define IMAKE_TEMPLATE\t\"%s\"\n", template);
- fprintf (tmpfile, "#define INCLUDE_IMAKEFILE\t\"%s\"\n", Imakefile);
- fprintf (tmpfile, "#include \"%s\"\n", template);
- start = buf;
- for (i = 0; i < st.st_size; ++i)
- *start++ = fgetc (infd);
- fclose (infd);
- buf[ st.st_size ] = '\0';
-
- punwritten = pbuf = buf;
- while (*pbuf) {
- /* pad make comments for cpp */
- if (*pbuf == '#' && (pbuf == buf || pbuf[-1] == '\n')) {
-
- ptoken = pbuf+1;
- while (*ptoken == ' ' || *ptoken == '\t')
- ptoken++;
- pend = ptoken;
- while (*pend && *pend != ' ' && *pend != '\t' && *pend != '\n')
- pend++;
- savec = *pend;
- *pend = '\0';
- if (strcmp(ptoken, "include")
- && strcmp(ptoken, "define")
- && strcmp(ptoken, "undef")
- && strcmp(ptoken, "ifdef")
- && strcmp(ptoken, "ifndef")
- && strcmp(ptoken, "else")
- && strcmp(ptoken, "endif")
- && strcmp(ptoken, "if")) {
- if (outFile == NULL) {
- tmpImakefile = mktemp(strdup(tmpImakefile));
- cleanedImakefile = tmpImakefile;
- outFile = fopen(tmpImakefile, "w");
- if (outFile == NULL)
- LogFatal("Cannot open %s for write.\n",
- tmpImakefile);
- }
- fwrite(punwritten, sizeof(char), pbuf-punwritten, outFile);
- fputs(" /**/", outFile);
- punwritten = pbuf;
- }
- *pend = savec;
- }
- pbuf++;
- }
- if (outFile) {
- fwrite(punwritten, sizeof(char), pbuf-punwritten, outFile);
- fclose(outFile); /* also closes the pipe */
- }
-
- /* Output the entire file */
- /* while (*buf)
- putc (*buf++, tmpfile);*/
- fclose (tmpfile);
- return(cleanedImakefile);
- }
-
- CleanCppOutput(tmpfd, tmpfname)
- FILE *tmpfd;
- char *tmpfname;
- {
- char *input;
- int blankline = 0;
- FILE *infile = fopen ("makefile.tmp", "r");
-
- while(input = ReadLine (infile, tmpfname)) {
- #ifdef os2
- if (*input == '\377')
- break;
- #endif
- if (isempty(input)) {
- if (blankline++)
- continue;
- KludgeResetRule();
- } else {
- blankline = 0;
- KludgeOutputLine(&input);
- fprintf (tmpfd, "%s",input);
- }
- fprintf (tmpfd, "\n");
- }
- fclose (tmpfd);
- fclose (infile);
- }
-
- /*
- * Determine if a line has nothing in it. As a side effect, we trim white
- * space from the end of the line. Cpp magic cookies are also thrown away.
- */
- isempty(line)
- char *line;
- {
- char *pend;
-
- /*
- * Check for lines of the form
- * # n "...
- * or
- * # line n "...
- */
- if (*line == '#') {
- pend = line+1;
- if (*pend == ' ')
- pend++;
- if (strncmp(pend, "line ", 5) == 0)
- pend += 5;
- if (isdigit(*pend)) {
- while (isdigit(*pend))
- pend++;
- if (*pend++ == ' ' && *pend == '"')
- return(TRUE);
- }
- }
-
- /*
- * Find the end of the line and then walk back.
- */
- for (pend=line; *pend; pend++) ;
-
- pend--;
- while (pend >= line && (*pend == ' ' || *pend == '\t'))
- pend--;
- *++pend = '\0';
- return (*line == '\0');
- }
-
- /*ARGSUSED*/
- char *ReadLine (tmpfd, tmpfname)
- FILE *tmpfd;
- char *tmpfname;
- {
- static boolean initialized = FALSE;
- static char *buf, *pline, *end;
- char *p1, *p2;
- char numbuf[10];
- int i,num;
-
- if (! initialized) {
- struct stat st;
- int i;
- /*
- * Slurp it all up.
- */
- fseek(tmpfd, 0, 0);
- fstat(fileno(tmpfd), &st);
- pline = buf = Emalloc(st.st_size+1);
- for (i = 0; i < st.st_size; ++i)
- buf[i] = getc (tmpfd);
- end = buf + st.st_size;
- *end = '\0';
- initialized = TRUE;
- }
-
- for (p1 = pline; p1 < end; p1++) {
- if (*p1 == '@' && *(p1+1) == '+') { /* increment number */
- i = 0;
- p2 = p1+2;
- while (isdigit(*p2))
- numbuf[i++] = *p2++;
- numbuf[i] = '\0';
- num = strlen(numbuf);
- sprintf(numbuf,"%d",atoi(numbuf)+1);
- p2 = numbuf;
- while(*p2)
- *p1++ = *p2++;
- *p1++ = ' '; /* skip over + character */
- if(strlen(numbuf) == num)
- *p1++ = ' ';
- continue;
- }
- else if (*p1 == '@' && *(p1+1) == '-') { /* decrement number */
- i = 0;
- p2 = p1+2;
- while (isdigit(*p2))
- numbuf[i++] = *p2++;
- numbuf[i] = '\0';
- num = strlen(numbuf);
- sprintf(numbuf,"%d",atoi(numbuf)-1);
- p2 = numbuf;
- while(*p2)
- *p1++ = *p2++;
- *p1++ = ' '; /* skip over - character */
- *p1++ = ' ';
- if(strlen(numbuf) != num)
- *p1++ = ' ';
- continue;
- }
- else if (*p1 == '@' && *(p1+1) == '#') { /* make comment */
- if (*(p1+2) == '#')
- *p1++ = '#';
- else {
- *p1++ = '#';
- *p1++ = ' ';
- }
- continue;
- }
- else if (*p1 == '@' && *(p1+1) == '!') { /* escaped-quote */
- *p1++ = '\\';
- *p1++ = '"';
- continue;
- }
- else if (*p1 == '@' && *(p1+1) == '/') { /* escaped-backslash */
- *p1++ = '\\';
- *p1++ = ' ';
- continue;
- }
- else if (*p1 == '@' && *(p1+1) == '@') { /* soft EOL */
- *p1++ = '\0';
- p1++; /* skip over second @ */
- break;
- }
- else if (*p1 == '\n') { /* real EOL */
- *p1++ = '\0';
- break;
- }
- }
-
- /*
- * return NULL at the end of the file.
- */
- p2 = (pline == p1 ? NULL : pline);
- pline = p1;
- return(p2);
- }
-
- writetmpfile(fd, buf, cnt)
- FILE *fd;
- int cnt;
- char *buf;
- {
- errno = 0;
- if (fwrite(buf, cnt, 1, fd) != 1)
- LogFatal("Cannot write to %s.", Makefile);
- }
-
- char *Emalloc(size)
- int size;
- {
- char *p, *malloc();
-
- if ((p = malloc(size)) == NULL)
- LogFatalI("Cannot allocate %d bytes\n", size);
- return(p);
- }
-
- KludgeOutputLine(pline)
- char **pline;
- {
- char *p = *pline;
-
- switch (*p) {
- case '#': /*Comment - ignore*/
- break;
- case '\t': /*Already tabbed - ignore it*/
- break;
- case ' ': /*May need a tab*/
- default:
- for (; *p; p++) if (p[0] == ':' &&
- p > *pline && p[-1] != '\\') {
- if (**pline == ' ')
- (*pline)++;
- InRule = TRUE;
- break;
- }
- if (InRule && **pline == ' ')
- **pline = '\t';
- break;
- }
- }
-
- KludgeResetRule()
- {
- InRule = FALSE;
- }
-
- char *strdup(cp)
- register char *cp;
- {
- register char *new = Emalloc(strlen(cp) + 1);
-
- strcpy(new, cp);
- return new;
- }
-
-
-